#ifndef D3D10GRAPHICS_H
#define D3D10GRAPHICS_H

#include "Graphics.h"
#include "Application.h"

#include <vector>
#include <algorithm>

#include <d3d10.h>
#include <d3dx10.h>

#define MAX_QUADS 16384
#define RESOURCE_FILENAME "GenBenD3D10.fx"

#define D3D10_ERR(func) \
{ \
   HRESULT hr = (func); \
   if(FAILED(hr)) \
   { \
		criticalError(#func " failed"); \
   } \
}

namespace GenBen {
	
class D3D10Texture : public Texture
{
public:
	D3D10Texture(ID3D10Device* device, const string& filename);
	virtual ~D3D10Texture();

	virtual uint getWidth();
	virtual uint getHeight();

	virtual void release();

	ID3D10ShaderResourceView* getResourceView();

	bool isReleased();

private:
	ID3D10ShaderResourceView* shader_resource_view;
	uint width, height;
	bool is_released;
};

#pragma pack(1)
struct D3D10RectVertex
{
	D3DXVECTOR4 source, dest, color;
	float depth, rotation;
};
#pragma pack()

struct D3D10Rect
{
	D3D10RectVertex vertex;
	D3D10Texture* texture;
	bool alpha;

	bool operator<(const D3D10Rect& q)
	{
		if(!alpha && !q.alpha)
			return texture < q.texture;
		
		if(alpha && q.alpha)
		{
			if(vertex.depth == q.vertex.depth)
				return texture < q.texture;;

			return vertex.depth < q.vertex.depth;
		}

		return q.alpha;
	}

	bool operator==(const D3D10Rect& q)
	{
		if(texture != q.texture)
			return false;

		if(vertex.depth != q.vertex.depth)
			return false;

		if(vertex.rotation != q.vertex.rotation)
			return false;

		if(vertex.source != q.vertex.source)
			return false;

		if(vertex.dest != q.vertex.dest)
			return false;

		if(vertex.color != q.vertex.color)
			return false;

		return true;
	}
};

struct D3D10TSpan
{
	uint first_rect;
	uint count;
};

class D3D10Graphics : public Graphics
{
public:
	D3D10Graphics(HWND window, uint width, uint height, uint scale, uint refresh_rate, bool fullscreen, bool lcd);
	virtual ~D3D10Graphics();

	virtual Texture* loadTexture(string filename);

	virtual string getDescription();
	
	virtual void clear(const Color& color);
	virtual void present();

	virtual void draw(Texture* texture, int layer, const RectI& source, const VectorI& dest, const Color& tint); 
	virtual void draw(Texture* texture, int layer, const RectI& source, const RectI& dest, const Color& tint); 
	virtual void draw(Texture* texture, int layer, const RectI& source, const VectorI& dest); 
	virtual void draw(Texture* texture, int layer, const RectI& source, const RectI& dest);

private:
	ID3D10Device* d3d_device;
	IDXGISwapChain* swap_chain;
	ID3D10RenderTargetView* render_target_view;
	ID3D10Texture2D* depth_stencil;
	ID3D10DepthStencilView* depth_stencil_view;
	ID3D10Effect* effect;
	ID3D10EffectTechnique* render_rects;

	ID3D10EffectShaderResourceVariable* effect_texture;

	ID3D10Buffer* rects_vb;
	ID3D10InputLayout* rects_vb_layout;

	std::vector<D3D10Rect> rects;
	std::vector<D3D10TSpan> texture_spans;
	uint rect_count;

	uint width, height;
};

}

#endif